﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
using AcctruePMS.Bll.Common;
using AcctrueWMS.Foundation.Common.Exception;
using AcctrueWMS.Foundation.DAL;

namespace AcctruePMS.Bll.Manager
{
    public struct MaterialFormat 
    {
        /// <summary>
        /// 物料编码长度
        /// </summary>
        public int MaterialNoLength;
        /// <summary>
        /// 属性码总长度
        /// </summary>
        public int PropertyLength;
        /// <summary>
        /// 批号长度
        /// </summary>
        public int BatchNoLength;

        /// <summary>
        /// 总长
        /// </summary>
        public int TotalLength;
    }

    public class MaterialManager
    {
        SysDictManager dictManager = new SysDictManager();
        SettingManager settingManager = new SettingManager();

        private MaterialFormat materialFormat;

        public MaterialManager()
        {
            string codeFormat = settingManager.GetSettingValue(SettingConst.MATERIALCODE_FORMAT);
            Regex reg = new Regex(@"{(?<len>\d+)}");

            MatchCollection matches = reg.Matches(codeFormat);
            if (matches.Count > 0)
                materialFormat.MaterialNoLength = int.Parse(matches[0].Groups["len"].Value);
            if (matches.Count > 1)
                materialFormat.PropertyLength = int.Parse(matches[1].Groups["len"].Value);
            if (matches.Count > 2)
                materialFormat.BatchNoLength = int.Parse(matches[2].Groups["len"].Value);
            materialFormat.TotalLength = materialFormat.MaterialNoLength + materialFormat.PropertyLength + materialFormat.BatchNoLength;
        }

        /// <summary>
        /// 根据物料条码，得到物料的名称
        /// </summary>
        /// <param name="materialCode">物料条码</param>
        /// <returns></returns>
        public string GetMaterialName(string materialCode)
        {
            if (string.IsNullOrEmpty(materialCode)) return string.Empty;

            if (materialCode.Length < materialFormat.MaterialNoLength) return string.Empty; 
            string materialName = null;
            //物料条码格式在词典中定义，形如{5}{8}{2}，分别为编码长度、属性长度和批号长度            
            string materialNo = materialCode.Substring(0, materialFormat.MaterialNoLength);
            materialName += GetMaterialNameByNo(materialNo);
            if (string.IsNullOrEmpty(materialName))
                throw new WMSBllException("找不到物料名称");
            //逐次读取属性，并按定义长度找到属性编码，之后找到属性名称
            DataTable propertyTable = GetPropertiesDefination(materialNo);
            int index = materialNo.Length;
            foreach (DataRow row in propertyTable.Rows)
            {
                int len = (int)row["propertyLength"];
                if ((index + len) > materialCode.Length)
                    break;
                string propertyCode = materialCode.Substring(index, len);
                materialName += " " + ParsePropertyName(propertyCode, row["propertyValue"].ToString());
                index += len;
            }
            return materialName;

        }

        public string GetMaterialNameByNo(string materialNo)
        {
            if (string.IsNullOrEmpty(materialNo)) return string.Empty;
            DataTable materialTable = GetMaterialInfo(materialNo);
            if (materialTable.Rows.Count == 0)
                throw new WMSBllException(string.Format("没有{0}这个物料", materialNo));
            return DataChecker.CheckForNull(materialTable.Rows[0]["materialName"]);

        }

        public DataTable GetMaterialInfo(string materialCode)
        {
            if (string.IsNullOrEmpty(materialCode)) return null;
            string materialNo = materialCode.Substring(0, materialFormat.MaterialNoLength);
            return WMSqlExcuter.ExecuteDataTable("select * from materials where materialNo=@materialNo",
                CommandType.Text,
                DBFactory.NewParameter("materialNo", materialNo));
        }

        public string GetMaterialNo(string materialCode)
        {
            if (string.IsNullOrEmpty(materialCode)) return null;
            string materialNo = materialCode.Substring(0, materialFormat.MaterialNoLength);
            return materialNo;
        }

        public string GetItemValue(string cloumnName, string materialCode)
        {
            if (string.IsNullOrEmpty(cloumnName) || string.IsNullOrEmpty(materialCode)) return string.Empty;
            if (materialCode.Length < materialFormat.MaterialNoLength) return null;
            string materialNo = materialCode.Substring(0, materialFormat.MaterialNoLength);
            return WMSqlExcuter.ExecuteScalar(string.Format("select top 1 {0} from materials  where materialNo='{1}' ", cloumnName, materialNo)).ToString();
        }


        public DataTable GetPropertiesDefination(string materialNo)
        {
            return WMSqlExcuter.ExecuteDataTable("select * from material_properties where materialNo=@materialNo order by sequence",
                CommandType.Text,
                DBFactory.NewParameter("materialNo", materialNo));
        }
        static Regex property_reg = new Regex(@"(?<code>\d+):(?<name>[^:;]+);");
        /// <summary>
        /// 得到属性名称
        /// </summary>
        /// <param name="propertyCode">属性编码</param>
        /// <param name="nameCollection">属性值。形如：01:黑;02:白;</param>
        /// <returns></returns>
        public string ParsePropertyName(string propertyCode, string nameCollection)
        {
            foreach (Match m in property_reg.Matches(nameCollection))
            {
                if (m.Groups["code"].Value == propertyCode)
                    return m.Groups["name"].Value;
            }
            return string.Empty;
        }

        //static Regex unit_reg = new Regex(@"(?<radix>\d+);");
        /// <summary>
        /// 返回单位转换表，列名为num0,num2,...
        /// </summary>
        /// <param name="materialNo">物料编码</param>
        /// <param name="unitIndex">单位索引，从1开始，指示是第几个单位</param>
        /// <param name="num">数量</param>
        /// <returns></returns>
        public DataTable UnitTransferWithIndex(string materialCode, int unitIndex, decimal num)
        {
            DataTable materialTable = GetMaterialInfo(materialCode);
            string[] radices = DataChecker.CheckForNull(materialTable.Rows[0]["conversion"]).Split('|');

            if (radices.Length < unitIndex)
                throw new WMSBllException(string.Format("索引{0}超出单位转换范围", unitIndex));

            decimal unitBase = decimal.Parse(radices[unitIndex]);

            //建立单位表
            DataTable unitTable = new DataTable();
            for (int i = 1; i <= radices.Length; i++)
            {
                unitTable.Columns.Add(string.Format("num{0}", i), typeof(decimal));
            }
            DataRow row = unitTable.NewRow();
            //根据所配置比例，进行计算
            for (int i = 1; i <= radices.Length; i++)
            {
                if (unitBase > 0)
                {
                    decimal radix = decimal.Parse(radices[i - 1]) / unitBase;
                    row[string.Format("num{0}", i)] = radix * num;
                }
            }
            unitTable.Rows.Add(row);

            return unitTable;
        }
        /// <summary>
        /// 返回单位转换表，列名为num0,num2,...
        /// </summary>
        /// <param name="materialCode">物料编码</param>
        /// <param name="unit">单位名称</param>
        /// <param name="num">数量</param>
        /// <returns></returns>
        public DataTable UnitTransfer(string materialCode, string unit, decimal num)
        {
            if (string.IsNullOrEmpty(materialCode) || string.IsNullOrEmpty(unit) || num==null) return null;

            DataTable materialTable = GetMaterialInfo(materialCode);
            int unitIndex = -1;
            int maxNum = int.Parse(settingManager.GetSettingValue(SettingConst.UNIT_MAXNUM));
            for (int i = 0; i < maxNum; i++)
            {
                string colName;
                if (i == 0)
                    colName = "unit";
                else
                    colName = string.Format("unit{0}", i + 1);

                //如果不包含列名，说明已超出单位最大个数
                if (!materialTable.Columns.Contains(colName))
                {
                    unitIndex = -1;
                    break;
                }
                if (DataChecker.CheckForNull(materialTable.Rows[0][colName]).Trim() == unit.Trim())
                {
                    unitIndex = i;
                    break;
                }
            }
            if (unitIndex == -1)
                throw new WMSBllException(string.Format("没有{0}这个单位", unit));
            return UnitTransferWithIndex(materialCode, unitIndex, num);
        }   

        public DataTable GetAllMaterialNo()
        {
            return WMSqlExcuter.ExecuteDataTable("select materialNo as [key],materialName as [value] from materials");
            //return WMSqlExcuter.ExecuteDataTable("select materialName+' | '+propertyname as[value],p.materialno+p.propertyvalue as [key] from materials m inner join material_properties p on m.materialNo=p.materialno");
        }

        /// <summary>
        /// 根据联想文本框的填入值得到后续应填入的值。如果字符串长度小于物料长度，显示物料；超出则显示下一个可选属性值。
        /// </summary>
        /// <param name="startWith"></param>
        /// <returns></returns>
        public DataTable GetAllMaterialNo(string startWith)
        {
            int len = startWith.Length;
            if (len < materialFormat.MaterialNoLength)
            {
                return WMSqlExcuter.ExecuteDataTable("select materialNo as [key],materialName as [value] from materials");
                //string strCmd = string.Format("select * from (select materialName+'*'+propertyname as[value],p.materialno+p.propertyvalue as [key] from materials m inner join material_properties p on m.materialNo=p.materialno) a where a.[key] like '{0}%'", startWith);
                //return WMSqlExcuter.ExecuteDataTable(strCmd);
            }
            else
            {
                string materialCode = startWith.Substring(0, materialFormat.MaterialNoLength);
                DataTable props = GetPropertiesDefination(materialCode);
                int l = materialFormat.MaterialNoLength;
                foreach (DataRow row in props.Rows)
                {
                    int pl = (int)row["propertyLength"];
                    if (l + pl <= len)
                    {
                        l += pl;
                        continue;
                    }
                    else
                    {
                        DataTable retTable = new DataTable();
                        retTable.Columns.Add("key");
                        retTable.Columns.Add("value");

                        string propValues = row["propertyValue"].ToString();
                        foreach (Match m in property_reg.Matches(propValues))
                        {
                            DataRow pRow = retTable.NewRow();
                            pRow["key"] = startWith.Substring(0, l) + m.Groups["code"].Value;
                            pRow["value"] = m.Groups["name"].Value;
                            retTable.Rows.Add(pRow);
                        }
                        return retTable;
                    }
                }
                return WMSqlExcuter.ExecuteDataTable("select materialNo as [key],materialName as [value] from materials where 1!=1");
            }
        }

        public DataTable GetAllNo(string tableName,string ColumnName)
        {
            return WMSqlExcuter.ExecuteDataTable(string.Format ("select {0} as [key],{0} as [value] from {1}",ColumnName,tableName));
        }

        public DataTable GetMaterialUnits(string materialCode)
        {
            if (string.IsNullOrEmpty(materialCode)) return null;

            if (materialCode.Length < materialFormat.MaterialNoLength) return null;
            string materialNo = materialCode.Substring(0, materialFormat.MaterialNoLength);
            int maxNum = int.Parse(settingManager.GetSettingValue(SettingConst.UNIT_MAXNUM));
            string cmdText = "select ";
            for (int i = 0; i < maxNum; i++)
            {
                string colName="unit";
                if(i>0)
                    colName+=(i+1).ToString();
                cmdText += colName;
                if (i < maxNum - 1)
                    cmdText += ",";
            }
            cmdText += " from materials where materialNo=@materialNo";
            return WMSqlExcuter.ExecuteDataTable(cmdText, CommandType.Text, DBFactory.NewParameter("materialNo", materialNo));
        }
    }
}
